﻿using System;
using System.Collections.Generic;
using System.Linq;
using Diploma.Models.IRepositories;

namespace Diploma.Models.Repositories
{
    internal class TasksRepository : ITasksRepository
    {
        private readonly DiplomaEntities dataContext;

        public TasksRepository(DiplomaEntities dataContext)
        {
            this.dataContext = dataContext;
        }


        public void Add(Task task, PlaningType planingType, QualificationLevel level, bool toAll)
        {
            GlobalTask globalTask = dataContext.CheckPoints.OfType<GlobalTask>().Where(
                gt => gt.StartDate > task.StartDate &&
                      gt.PlaningTypeId == planingType.PlaningTypeId &&
                      gt.QualificationLevelId == level.QualificationLevelId &&
                      gt.DeletionDate == null).
                OrderBy(gt => gt.StartDate).FirstOrDefault();
            if (globalTask == null)
                return;

            if (toAll)
            {
                CollaborationRoom currentRoom =
                    dataContext.CollaborationRooms.Where(r => r.CollaborationRoomId == task.CollaborationRoomId).
                        FirstOrDefault();
                if (currentRoom == null)
                    throw new Exception();
                IEnumerable<CollaborationRoom> allLecturerRooms =
                    currentRoom.Lecturer.CollaborationRooms.Where(r => r.Student != null);
                foreach (CollaborationRoom room in allLecturerRooms)
                {
                    var newTask = new Task
                                      {
                                          CheckPointId = Guid.NewGuid(),
                                          GlobalTask = globalTask,
                                          RemindInDays = 3,
                                          StartDate = task.StartDate,
                                          CollaborationRoom = room,
                                          Description = task.Description,
                                          Name = task.Name,
                                      };
                    if (newTask.CollaborationRoomId == task.CollaborationRoomId)
                        newTask.PrevCheckPoint = task.PrevCheckPoint;

                    dataContext.AddToCheckPoints(newTask);
                }
            }

            else
            {
                task.CheckPointId = Guid.NewGuid();

                task.GlobalTask = globalTask;

                task.RemindInDays = 3;
                if (task.PrevCheckPointId != null)
                {
                    Task prevTask = GetTask(task.PrevCheckPointId.Value);
                    if (!prevTask.IsCompleted && task.IsCompleted)
                        task.IsCompleted = false;
                }
                dataContext.AddToCheckPoints(task);
            }

            dataContext.SaveChanges();
        }

        public void Edit(Task task, PlaningType planingType)
        {
            Task oldTask = GetTask(task.CheckPointId);
            if (oldTask == null)
                throw new Exception();

            GlobalTask globalTask = dataContext.CheckPoints.OfType<GlobalTask>().Where(
                gt => gt.StartDate > task.StartDate &&
                      gt.PlaningTypeId == planingType.PlaningTypeId &&
                      gt.QualificationLevelId == oldTask.CollaborationRoom.Student.StudentsGroup.QualificationLevelId &&
                      gt.DeletionDate == null).
                OrderBy(gt => gt.StartDate).FirstOrDefault();
            if (globalTask == null)
                return;
            oldTask.PrevCheckPointId = task.PrevCheckPointId;
            oldTask.Name = task.Name;
            oldTask.StartDate = task.StartDate;
            if (oldTask.GlobalTask.PlaningType != planingType)
            {
                oldTask.PrevCheckPoint = null;
                foreach (CheckPoint nextTask in oldTask.NextCheckPoints)
                {
                    nextTask.PrevCheckPoint = oldTask.PrevCheckPoint;
                }
            }

            if (!oldTask.IsCompleted && task.IsCompleted)
            {
                if (oldTask.CompletionDate == null)
                {
                    oldTask.CompletionDate = DateTime.Today;
                }
                else if (oldTask.CompletionDate < DateTime.Today)
                {
                    oldTask.CompletionDate = DateTime.Today;
                }
            }

            oldTask.GlobalTask = globalTask;
            oldTask.CollaborationRoomId = task.CollaborationRoomId;
            oldTask.Description = task.Description;
            oldTask.IsCompleted = task.IsCompleted;
            if (!task.IsCompleted)
            {
                foreach (Task nextTask in oldTask.NextCheckPoints.OfType<Task>())
                {
                    nextTask.IsCompleted = false;
                }
            }
            else
            {
                if (task.PrevCheckPointId != null)
                {
                    Task prevTask = GetTask(task.PrevCheckPointId.Value);
                    if (!prevTask.IsCompleted)
                        oldTask.IsCompleted = false;
                }
            }
             
           dataContext.SaveChanges();
        }

        public void Delete(Task task)
        {
            foreach (CheckPoint nextTask in task.NextCheckPoints.ToList())
            {
                nextTask.PrevCheckPoint = (task.PrevCheckPoint == null) ? null : task.PrevCheckPoint;
            }

            task.DeletionDate = DateTime.Now;
            //_dataContext.DeleteObject(task);
            dataContext.SaveChanges();
        }

        public Task GetTask(Guid id)
        {
            return
                dataContext.CheckPoints.OfType<Task>().Where(gt => gt.CheckPointId == id && gt.DeletionDate == null).
                    FirstOrDefault();
        }

        public IEnumerable<Task> GetTasks(CollaborationRoom room, PlaningType planingType)
        {
            return dataContext.CheckPoints.OfType<Task>().Where(t =>
                                                                 t.CollaborationRoomId == room.CollaborationRoomId &&
                                                                 t.GlobalTask.PlaningTypeId == planingType.PlaningTypeId &&
                                                                 t.DeletionDate == null);
        }

        public IEnumerable<Task> GetTasksWithDateLower(CollaborationRoom room, PlaningType planingType, DateTime? date)
        {
            IEnumerable<Task> tasks = GetTasks(room, planingType);
            if (date != null)
            {
                tasks = from t in tasks
                        where t.StartDate.Value < date.Value &&
                              t.DeletionDate == null
                        orderby t.StartDate
                        select t;
            }
            return tasks;
        }

        public bool TaskCanBeAdded(Task task, int planingTypeId)
        {
            CollaborationRoom room = dataContext.CollaborationRooms.Where(r =>
                                                                           r.CollaborationRoomId ==
                                                                           task.CollaborationRoomId &&
                                                                           r.DeletionDate == null).FirstOrDefault();
            PlaningType planingType =
                dataContext.PlaningTypes.Where(pt => pt.PlaningTypeId == planingTypeId).FirstOrDefault();

            bool tasksKeepFromAddingExist = true;

            IEnumerable<Task> tasks = GetTasks(room, planingType).Where(t => t.StartDate == task.StartDate);

            if (tasks.Count() == 1 && tasks.First().CheckPointId == task.CheckPointId)
                return true;

            tasksKeepFromAddingExist = tasks.Count() != 0;

            bool globalTasksKeepFromAddingExist = dataContext.CheckPoints.OfType<GlobalTask>().Where(gt =>
                                                                                                      gt.PlaningTypeId ==
                                                                                                      planingTypeId &&
                                                                                                      gt.
                                                                                                          QualificationLevelId ==
                                                                                                      room.Student.
                                                                                                          StudentsGroup.
                                                                                                          QualificationLevelId &&
                                                                                                      gt.StartDate ==
                                                                                                      task.StartDate &&
                                                                                                      gt.DeletionDate ==
                                                                                                      null).Count() != 0;

            bool globalTasksForTaskNotExist = dataContext.CheckPoints.OfType<GlobalTask>().Where(gt =>
                                                                                                    gt.PlaningTypeId ==
                                                                                                    planingTypeId &&
                                                                                                    gt.
                                                                                                        QualificationLevelId ==
                                                                                                    room.Student.
                                                                                                        StudentsGroup.
                                                                                                        QualificationLevelId &&
                                                                                                    gt.StartDate >
                                                                                                    task.StartDate &&
                                                                                                    gt.DeletionDate ==
                                                                                                    null).Count() == 0;

            if (tasksKeepFromAddingExist || globalTasksKeepFromAddingExist || globalTasksForTaskNotExist)
                return false;
            return true;
        }

        public void SetCompletion(Task task, bool isCompleted)
        {
            task.IsCompleted = (bool)isCompleted;
            if(isCompleted)
            task.CompletionDate = DateTime.Today;
            if (!task.IsCompleted)
            {
                foreach (Task nextTask in task.NextCheckPoints.OfType<Task>())
                {
                    nextTask.IsCompleted = false;
                }
            }
            dataContext.SaveChanges();
        }
    }
}